package xyz.syyrjx.registry.constant;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xyz.syyrjx.entity.SyyrjxRpcRemoteAddressRegistryEntity;
import xyz.syyrjx.entity.SyyrjxRpcRemoteAddress;
import xyz.syyrjx.registry.task.SyyrjxRpcRegistrySynchronizeTask;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @author 大地崩坏苍蝇兽
 * @date 2023/1/12 - 15:44
 */
public class SyyrjxRpcProviderRegistryTable {

    private static int microSecondsToDead;

    private static final Logger LOGGER = LoggerFactory.getLogger(SyyrjxRpcProviderRegistryTable.class);

    private static final Map<String, Set<SyyrjxRpcRemoteAddress>> PROVIDER_MAP = new ConcurrentHashMap<>();

    private static final Queue<SyyrjxRpcRemoteAddressRegistryEntity> LAST_HEARTBEAT_TIME_LIST = new LinkedList<>();

    private static final Set<SyyrjxRpcRemoteAddress> DEAD_REMOTE_HOST_SET = new CopyOnWriteArraySet<>();

    /**
     * 注册提供者远程地址到注册中心
     * @param providerName 提供者名
     * @param remoteAddress 远程地址
     */
    public static void registry(String providerName, SyyrjxRpcRemoteAddress remoteAddress) {
        Set<SyyrjxRpcRemoteAddress> set = PROVIDER_MAP.get(providerName);
        if (set == null) {
            set = PROVIDER_MAP.putIfAbsent(providerName, new CopyOnWriteArraySet<>());
            if (set == null) {
                set = PROVIDER_MAP.get(providerName);
            }
        }

        //添加到远程主机列表，从死亡名单中删除
        set.add(remoteAddress);
        DEAD_REMOTE_HOST_SET.remove(remoteAddress);

        //更新心跳时间
        SyyrjxRpcRemoteAddressRegistryEntity entity = remoteAddress.toRegistryEntity();
        LAST_HEARTBEAT_TIME_LIST.remove(entity);
        LAST_HEARTBEAT_TIME_LIST.add(entity);

        LOGGER.debug("注册结束当前提供者有" + PROVIDER_MAP);
        LOGGER.debug("已经死亡的提供者有" + DEAD_REMOTE_HOST_SET);
    }

    /**
     * 同步提供者地址
     * @param providerAddressMap 提供者即地址集合映射表
     */
    public static void synchronize(Map<String, Set<SyyrjxRpcRemoteAddress>> providerAddressMap){
        LOGGER.debug("开始同步，接收到的提供者有" + PROVIDER_MAP.toString());
        for (String provider : providerAddressMap.keySet()) {
            //这个提供者存在
            if (PROVIDER_MAP.containsKey(provider)) {
                PROVIDER_MAP.get(provider).addAll(providerAddressMap.get(provider));
            }else {
                Set<SyyrjxRpcRemoteAddress> addresses = PROVIDER_MAP.getOrDefault(provider,new CopyOnWriteArraySet<>());
                for (SyyrjxRpcRemoteAddress address : addresses) {
                    //更新心跳
                    SyyrjxRpcRemoteAddressRegistryEntity newHeartBeat = address.toRegistryEntity();
                    if (!LAST_HEARTBEAT_TIME_LIST.contains(newHeartBeat)) {
                        LAST_HEARTBEAT_TIME_LIST.add(newHeartBeat);
                    }
                }
                addresses.addAll(providerAddressMap.get(provider));
                //提供者已经被别的线程写入
                if (PROVIDER_MAP.containsKey(provider)){
                    PROVIDER_MAP.get(provider).addAll(providerAddressMap.get(provider));
                }else {
                    PROVIDER_MAP.put(provider, addresses);
                }
                for (SyyrjxRpcRemoteAddress address : addresses) {
                    if (!LAST_HEARTBEAT_TIME_LIST.contains(address)) {
                        LAST_HEARTBEAT_TIME_LIST.add(address.toRegistryEntity());
                    }
                }
            }
        }
        LOGGER.debug("同步结束，当前提供者有" + PROVIDER_MAP.toString());
    }

    public static void registry(String[] providerNames, SyyrjxRpcRemoteAddress remoteAddress) {
        for (String providerName : providerNames) {
            registry(providerName, remoteAddress);
        }
    }

    /**
     * 获取存货的提供者地址
     * @param providerName 提供者名
     * @return 存活的提供者地址集合
     */
    public static Set<SyyrjxRpcRemoteAddress> call(String providerName) {
        Set<SyyrjxRpcRemoteAddress> registrySet = PROVIDER_MAP.get(providerName);
        Set<SyyrjxRpcRemoteAddress> addresses = new HashSet<>();
        if (registrySet == null) {
            return addresses;
        }
        for (SyyrjxRpcRemoteAddress remoteAddress : registrySet) {
            if (!DEAD_REMOTE_HOST_SET.contains(remoteAddress)) {
                addresses.add(remoteAddress);
            }
        }
        return addresses;
    }

    /**
     * 检查注册时间。将已经超过时间未发送心跳的远程主机放到死亡队列
     */
    public static void updateAliveList() {
        long now = System.currentTimeMillis();
        while (LAST_HEARTBEAT_TIME_LIST .size() != 0 &&
                now - LAST_HEARTBEAT_TIME_LIST.peek().getTime() > microSecondsToDead) {
            LOGGER.debug("这次挂掉的地址为" + LAST_HEARTBEAT_TIME_LIST.peek());
            SyyrjxRpcRemoteAddress address = LAST_HEARTBEAT_TIME_LIST.poll().getAddress();
            DEAD_REMOTE_HOST_SET.add(address);
        }
    }


    public static void setSecondsToDead(int microSecondsToDead) {
        SyyrjxRpcProviderRegistryTable.microSecondsToDead = microSecondsToDead;
    }

    /**
     * 获取还存活的提供者
     * @return 还存活的提供者地址
     */
    public static Map<String,Set<SyyrjxRpcRemoteAddress>> getProviderMapAlive() {
        Map<String,Set<SyyrjxRpcRemoteAddress>> providerAddressesMap = new HashMap<>();
        for (Map.Entry<String, Set<SyyrjxRpcRemoteAddress>> entry : PROVIDER_MAP.entrySet()) {
            Set<SyyrjxRpcRemoteAddress> addresses = new HashSet<>();
            Set<SyyrjxRpcRemoteAddress> addressNotSelect = entry.getValue();
            for (SyyrjxRpcRemoteAddress address : addressNotSelect) {
                if (!DEAD_REMOTE_HOST_SET.contains(address)) {
                    addresses.add(address);
                }
            }
            if (addresses.size() != 0) {
                providerAddressesMap.put(entry.getKey(), addresses);
            }
        }
        return providerAddressesMap;
    }


}
